package com.shop.merchant.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.ex.ShoppingException;
import com.shop.mapper.MessageMapper;
import com.shop.merchant.Interceptor.GetMerchantInfoInterceptor;
import com.shop.merchant.config.RedissonConfig;
import com.shop.merchant.mapper.GoodsBaseMapper;
import com.shop.merchant.mapper.GoodsCategoryMapper;
import com.shop.merchant.mapper.GoodsImageMapper;
import com.shop.merchant.mapper.PriceIdMapper;
import com.shop.merchant.po.GoodsBase;
import com.shop.merchant.po.GoodsCategory;
import com.shop.merchant.po.Merchant;
import com.shop.merchant.po.PriceId;
import com.shop.merchant.po.RedisLogic.RedisData;
import com.shop.merchant.service.GoodsBaseService;
import com.shop.merchant.service.GoodsImageService;
import com.shop.po.GoodsImage;
import com.shop.po.Message;
import com.shop.po.dto.GoodsInfo;
import org.apache.logging.log4j.util.Strings;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author banxia
 * @since 2023-02-24
 */
@Service
public class GoodsBaseServiceImpl extends ServiceImpl<GoodsBaseMapper, GoodsBase> implements GoodsBaseService {


    @Autowired
    private GoodsBaseMapper goodsBaseMapper;
    @Autowired
    private GoodsCategoryMapper goodsCategoryMapper;
    @Autowired//用其一次性插入多条数据的功能
    private GoodsImageService goodsImageService;
    @Autowired
    private GoodsImageMapper goodsImageMapper;
    @Autowired
    private PriceIdMapper goodsPriceMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
//    private MessageService messageService;
    private MessageMapper messageMapper;


    @Override
    public void goodsCountUpdate(Long goodsId, Long count) {
        GoodsBase goodsBase = new GoodsBase();
        goodsBase.setId(goodsId);
        int i=goodsBaseMapper.goodsCountUpdate(goodsId,count);
        if (i == 0) {
            ShoppingException.ThrowShoppingException("修改库存失败");
        }
    }

    @Override
    public GoodsInfo getByGoodsIdFromDb(Long id) {
        GoodsInfo goodsInfo = new GoodsInfo();
        //（1）查询基础信息
        GoodsBase goodsBase = goodsBaseMapper.selectById(id);
        if (goodsBase==null){
            ShoppingException.ThrowShoppingException("商品不存在");
        }
        BeanUtils.copyProperties(goodsBase,goodsInfo);
        //（2）查询分类
        Long categoryId = goodsBase.getCategoryId();
        GoodsCategory goodsCategory = goodsCategoryMapper.selectById(categoryId);
        if (goodsCategory != null) {
            goodsInfo.setCategoryName(goodsCategory.getName());
        }
        //（3）价格
        Long priceId = goodsBase.getPriceId();
        PriceId price = goodsPriceMapper.selectById(priceId);
        if (price != null) {
            BeanUtils.copyProperties(price,goodsInfo);
        }
        //（4）查询图片
        LambdaQueryWrapper<GoodsImage> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(GoodsImage::getGoodsId,id);
        List<GoodsImage> goodsImages = goodsImageMapper.selectList(queryWrapper);
        goodsInfo.setImageList(goodsImages);
        return goodsInfo;
    }

    @Override
    public GoodsInfo getByGoodsIdFromRedis(Long id) {
        String redisDataJson = stringRedisTemplate.opsForValue().get("goods:" + id);
        if (redisDataJson==null){
            ShoppingException.ThrowShoppingException("商品不存在");
        }
        RedisData redisData = JSONObject.parseObject(redisDataJson, RedisData.class);
        LocalDateTime expireTime = redisData.getExpireTime();//获取过期时间
        Object data = redisData.getData();
        String dataJson = data.toString();
        GoodsInfo goodsInfo = JSONObject.parseObject(dataJson, GoodsInfo.class);
        if (expireTime.isAfter(LocalDateTime.now())){
            //未过期
            return goodsInfo;
        }
        //过期，代处理
        System.out.println("==================================");
        System.out.println("数据已过期");
        System.out.println("==================================");
        RedissonConfig redissonConfig=new RedissonConfig();
        RedissonClient redissonClient = redissonConfig.redissonClient();
        RLock lock = redissonClient.getLock("goodsPublish");
        //尝试获取锁
        if (lock.tryLock()){
            System.out.println("------------------------------------");
            System.out.println("获取到分布式锁->再次查询redis");
            System.out.println("------------------------------------");
            //获取到锁
            //再次查询redis
            String dataJSON = stringRedisTemplate.opsForValue().get("goods:" + id);
            RedisData rd = JSONObject.parseObject(dataJSON, RedisData.class);
            LocalDateTime expireTime1 = rd.getExpireTime();//获取过期时间
            //获取新的数据（可能还是老数据）
            goodsInfo=JSONObject.parseObject(rd.getData().toString(),GoodsInfo.class);
            if (expireTime1.isBefore(LocalDateTime.now())){
                log.debug("=================================================");
                log.debug("缓存依旧过期，只能查询DB");
                log.debug("=================================================");
                //依旧过期->查询DB->调用上述查询DB的方法即可
                goodsInfo = getByGoodsIdFromDb(id);
                //缓存新数据到redis
                RedisData rd2 = new RedisData();
                //这里为了测试方便暂时将 有效期 设置为1小时
                rd2.setExpireTime(LocalDateTime.now().plusSeconds(60*60));
                rd2.setData(goodsInfo);
                //转为json字符串
                String newRedisDataJson = JSONObject.toJSONString(rd2);
                //存到redis
                stringRedisTemplate.opsForValue().set("goods:"+id,newRedisDataJson);
                log.debug("=================================================");
                log.debug("已将新数据设置到redis中");
                log.debug("=================================================");
            }
            //已经被其他线程缓存到redis了，
            //释放分布式锁，返回goodsInfo
            lock.unlock();
            return goodsInfo;
        }else{
            //获取不到锁，直接返回
            return goodsInfo;
        }
    }


    /**
     * 查询商品，白名单，也可以为商家查询商品特有！
     * @param likeName :商品名称模糊匹配 (require=false)
     * @param minPrice ：最低价格  (require=false)
     * @param maxPrice ：最高价格  (require=false)
     * @param categoryName ：分类名称  (require=false)
     * @param page ：第几页
     * @param size ：每页大小
     * @return
     */
    @Override
    public List<GoodsInfo> getGoodsList(String likeName, Long minPrice,
                            Long maxPrice, String categoryName,
                             Integer page, Integer size) {
        Merchant merchant = GetMerchantInfoInterceptor.getMerchant();
        Long merchantId=null;
        if (merchant!=null){
            //查询本店的东西。
            merchantId=merchant.getId();
        }
        List<GoodsInfo> goodsList=goodsBaseMapper.getGoodsList(likeName,minPrice,maxPrice,categoryName,
                                    merchantId,page,size);
        return goodsList;
    }



    @Override
    @Transactional
    public void publishGoods(GoodsInfo goodsInfo) {
        Merchant merchant = GetMerchantInfoInterceptor.getMerchant();
        if (merchant==null || merchant.getId()==null){
            ShoppingException.ThrowShoppingException("请先登录！");
        }
        goodsInfo.setMerchantId(merchant.getId());
        goodsInfo.setMerchantName(merchant.getName());
        goodsInfo.setType(1);
        //查看该分类是否存在->设置分类id
        LambdaQueryWrapper<GoodsCategory> categoryWrapper=new LambdaQueryWrapper<GoodsCategory>();
        categoryWrapper.eq(GoodsCategory::getName,goodsInfo.getCategoryName());
        GoodsCategory one = goodsCategoryMapper.selectOne(categoryWrapper);
        if (one==null){
            ShoppingException.ThrowShoppingException("该分类名称不存在！");
        }
        GoodsBase goodsBase = new GoodsBase();
        goodsBase.setCategoryId(one.getId());
        PriceId goodsPrice = new PriceId();
        //初始化
        BeanUtils.copyProperties(goodsInfo,goodsBase);
        BeanUtils.copyProperties(goodsInfo,goodsPrice);
        //先将销售插入到数据库中
        goodsPriceMapper.insert(goodsPrice);
        //在将base插入到数据库中
        goodsBase.setPriceId(goodsPrice.getId());
        goodsBaseMapper.insert(goodsBase);
        //获取到商品base的id
        Long baseId = goodsBase.getId();
        //准备插入图片数据
        List<GoodsImage> imageList = goodsInfo.getImageList();
        //设置其goodId
        imageList.forEach(e->e.setGoodsId(baseId));

        //批量插入图片数据
        goodsImageService.saveBatch(imageList);

        //将goodsBase的id插入到数据库中
        Long id = goodsBase.getId();
        Message message=new Message();
        message.setMessageType("goodsPublic");
        message.setBusinessKey1(id.toString());
        messageMapper.insert(message);

    }

    @Override
    public void changGoodsStatus(Long id,Integer type) {
        GoodsBase goodsBase = new GoodsBase();
        goodsBase.setType(type);
        LambdaQueryWrapper<GoodsBase> queryWrapper=new LambdaQueryWrapper<>();
        Merchant merchant = GetMerchantInfoInterceptor.getMerchant();
        if (merchant == null) {
            ShoppingException.ThrowShoppingException("请先登录");
        }
        Long merchantId = merchant.getId();
        queryWrapper.eq(GoodsBase::getMerchantId,merchantId);
        queryWrapper.eq(GoodsBase::getId,id);
        int i = goodsBaseMapper.update(goodsBase, queryWrapper);
        if (i == 0) {
            ShoppingException.ThrowShoppingException("不可修改其他商家的商品！！");
        }
    }

    @Override
    public Integer getTotal(String name,Long categoryId) {
        Merchant merchant = GetMerchantInfoInterceptor.getMerchant();
        if (merchant==null || merchant.getId()==null){
            ShoppingException.ThrowShoppingException("请先登录");
        }
        LambdaQueryWrapper<GoodsBase> wrapper=new LambdaQueryWrapper();
        wrapper.eq(GoodsBase::getMerchantId,merchant.getId());
        wrapper.like(Strings.isNotBlank(name),GoodsBase::getName,name);
        if (categoryId != null) {
            wrapper.eq(GoodsBase::getCategoryId,categoryId);
        }
        Integer count = baseMapper.selectCount(wrapper);
        return count;
    }

    @Override
    public void deleteGoods(Long id) {
        GoodsBase goodsBase = goodsBaseMapper.selectById(id);
        if (goodsBase == null) {
            ShoppingException.ThrowShoppingException("商品数据不存在");
        }
        //删除goodsBase
        int b1 = goodsBaseMapper.deleteById(id);
        //删除goodsImage
        LambdaQueryWrapper<GoodsImage> wrapperImage=new LambdaQueryWrapper();
        wrapperImage.eq(GoodsImage::getGoodsId,id);
        int b2 = goodsImageMapper.delete(wrapperImage);
        //删除goodsPrice
        int b3 = goodsPriceMapper.deleteById(goodsBase.getPriceId());
        if (b1*b2*b3==0){
            ShoppingException.ThrowShoppingException("删除失败,b1,b2,b3分别为:"+b1+b2+b3);
        }
    }

    @Override
    public Long UserGetTotal(String likeName, Long minPrice, Long maxPrice, String categoryName) {
        return goodsBaseMapper.UserGetTotal(likeName, minPrice, maxPrice, categoryName);
    }

}
